package dk.pun.aot.client;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.RunAsyncCallback;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;

import dk.pun.aot.client.event.CharacterSelectedEvent;
import dk.pun.aot.client.event.DiceRolledEvent;
import dk.pun.aot.client.event.DiceRolledEventHandler;
import dk.pun.aot.client.event.SelectCharacterEvent;
import dk.pun.aot.client.event.SelectCharacterEventHandler;
import dk.pun.aot.client.event.SystemMessageUpdatedEvent;
import dk.pun.aot.client.event.SystemMessageUpdatedEventHandler;
import dk.pun.aot.client.event.ViewCharacterEvent;
import dk.pun.aot.client.event.ViewCharacterEventHandler;
import dk.pun.aot.client.presenter.MainPresenter;
import dk.pun.aot.client.presenter.Presenter;
import dk.pun.aot.client.presenter.SelectCharacterPresenter;
import dk.pun.aot.client.presenter.ViewCharacterPresenter;
import dk.pun.aot.client.view.MainView;
import dk.pun.aot.client.view.MainViewImpl;
import dk.pun.aot.client.view.SelectCharacterViewImpl;
import dk.pun.aot.client.view.ViewCharacterViewImpl;
import dk.pun.aot.client.widget.DiceRollHistoryPanel;
import dk.pun.aot.shared.user.LoginInfo;

public class Controller implements Presenter, ValueChangeHandler<String> {

	private final LoginInfo loginInfo;
	private final AlphaOmegaToolsServiceAsync rpcService;
	private final HandlerManager eventBus;
	private HasWidgets container;
	
	// Presenters
	private MainPresenter mainPresenter;
	private ViewCharacterPresenter viewCharacterPresenter;
	// private ModifyCharacterPresenter modifyCharacterPresenter;
	// private DailyLifePresenter DailyLifePresenter;
	private SelectCharacterPresenter selectCharacterPresenter;
	private DiceRollHistoryPanel diceRollHistoryPanel;

	public Controller(LoginInfo loginInfo, AlphaOmegaToolsServiceAsync rpcService, HandlerManager eventBus) {
		this.loginInfo = loginInfo;
		this.rpcService = rpcService;
		this.eventBus = eventBus;
		this.diceRollHistoryPanel = new DiceRollHistoryPanel();
		this.bind();
	}

	private void bind() {
		History.addValueChangeHandler(this);
		
		this.eventBus.addHandler(ViewCharacterEvent.TYPE,
				new ViewCharacterEventHandler() {
					public void onViewCharacter(ViewCharacterEvent event) {
						doViewCharacter();
					}
				});

		this.eventBus.addHandler(SelectCharacterEvent.TYPE,
				new SelectCharacterEventHandler() {
					public void onSelectCharacter(SelectCharacterEvent event) {
						doSelectCharacter();
					}
				});

		this.eventBus.addHandler(DiceRolledEvent.TYPE, new DiceRolledEventHandler() {
			public void onDiceRolled(DiceRolledEvent event) {
				doDiceRolled(event);
			}
		});
		
		this.eventBus.addHandler(SystemMessageUpdatedEvent.TYPE, new SystemMessageUpdatedEventHandler() {
			
			@Override
			public void onSystemMessageUpdated(SystemMessageUpdatedEvent event) {
				rpcService.setMessage(event.getMessage(), new AsyncCallback<Void>() {

					@Override
					public void onFailure(Throwable caught) {
						GWT.log("Failed to update system message: ", caught);
					}

					@Override
					public void onSuccess(Void result) {
					}
				});
			}
		});
	}

	private void doViewCharacter() {
		History.newItem("viewCharacter");
	}
	
	private void doSelectCharacter() {
		History.newItem("selectCharacter");
	}
	
	private void doDiceRolled(DiceRolledEvent event) {
		this.diceRollHistoryPanel.addDiceRoll(event.getDiceRoll());
	}

	public void go(final HasWidgets rootContainer) {
		MainView mainView = new MainViewImpl(this.loginInfo);
		this.mainPresenter = new MainPresenter(eventBus, mainView);
		this.mainPresenter.go(rootContainer);
		this.container = mainView.getCenterPanel();

		this.eventBus.fireEvent(new CharacterSelectedEvent(this.loginInfo.getUserData().getSelectedCharacterId()));

		if ("".equals(History.getToken())) {
			History.newItem("selectCharacter");
		} else {
			History.fireCurrentHistoryState();
		}
	}

	public void onValueChange(ValueChangeEvent<String> event) {
		if (this.loginInfo.isAnonymous() && !AnonymousLogin.isLoggedIn()) {
			Window.Location.assign(this.loginInfo.getLogoutURL());
		} else {
			String token = event.getValue();
			if (token != null) {
				if (token.equals("viewCharacter")) {
					GWT.runAsync(new RunAsyncCallback() {
						public void onFailure(Throwable caught) {
						}
	
						public void onSuccess() {
							if (viewCharacterPresenter == null) {
								viewCharacterPresenter = new ViewCharacterPresenter(loginInfo.getUserData(), rpcService, eventBus, new ViewCharacterViewImpl(diceRollHistoryPanel));
							}
							mainPresenter.setTabFocus(MainView.MainViewTab.VIEW_CHARACTER);
							viewCharacterPresenter.go(container);
							rpcService.getMessage(new AsyncCallback<String>() {
								
								@Override
								public void onFailure(Throwable caught) { }
								
								@Override
								public void onSuccess(String result) {
									mainPresenter.setMessage(result);
								}
							});
						}
					});
				} else if (token.equals("selectCharacter")) {
					GWT.runAsync(new RunAsyncCallback() {
						public void onFailure(Throwable caught) {
						}
	
						public void onSuccess() {
							if (selectCharacterPresenter == null) {
								selectCharacterPresenter = new SelectCharacterPresenter(loginInfo.getUserData(), rpcService, eventBus, new SelectCharacterViewImpl());
							}
							mainPresenter.setTabFocus(null);
							selectCharacterPresenter.go(container);
							rpcService.getMessage(new AsyncCallback<String>() {
								
								@Override
								public void onFailure(Throwable caught) { }
								
								@Override
								public void onSuccess(String result) {
									mainPresenter.setMessage(result);
								}
							});
						}
					});
				}
			}
		}
	}
	
}
